﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GeneticAlgorythm.Algorythm
{
    public class UniformOrderBasedCrossover : Crossover
    {
        private PermutationChromosome _firstParentChromosome;
        private PermutationChromosome _secondParentChromosome;
        private PermutationChromosome _firstChilrdrenChromosome;
        private PermutationChromosome _secondChildrenChromosome;
        private List<bool> _bitMask = null;
        private int _chromosomeSize;

        public UniformOrderBasedCrossover(){}

        public UniformOrderBasedCrossover(List<bool> bitMask)
        {
            this._bitMask = bitMask;

        }

        public List<Chromosome> execute(Chromosome firstParent, Chromosome secondParent)
        {
            setUps(firstParent, secondParent);

            copyParentGenesDependingOnMask();

            fillRemainingGenes();

            return new List<Chromosome> {_firstChilrdrenChromosome, _secondChildrenChromosome};
        }

        private void setUps(Chromosome firstParent, Chromosome secondParent)
        {
            _firstParentChromosome = (PermutationChromosome) firstParent;
            _secondParentChromosome = (PermutationChromosome) secondParent;
            _chromosomeSize = _firstParentChromosome.getSize();
            if (_bitMask == null)
                _bitMask = RandomGenerator.getInstance().generateBitVector(_chromosomeSize);
            _firstChilrdrenChromosome = new PermutationChromosome(_chromosomeSize);
            _secondChildrenChromosome = new PermutationChromosome(_chromosomeSize);
        }



        private void copyParentGenesDependingOnMask()
        {
            for (int i = 0; i < _chromosomeSize; i++)
            {
                if (_bitMask[i].Equals(false))
                    _firstChilrdrenChromosome.setGene(i, _firstParentChromosome.getGene(i));
                else
                    _secondChildrenChromosome.setGene(i, _secondParentChromosome.getGene(i));
            }
        }

        private void fillRemainingGenes()
        {
            for (int i = 0; i < _chromosomeSize; i++)
            {
                if (_bitMask[i].Equals(true))
                {
                    int j = 0;
                    while (_firstChilrdrenChromosome.contains(_secondParentChromosome.getGene(j))) j++;
                    _firstChilrdrenChromosome.setGene(i, _secondParentChromosome.getGene(j));
                }
                else
                {
                    int j = 0;
                    while (_secondChildrenChromosome.contains(_firstParentChromosome.getGene(j))) j++;
                    _secondChildrenChromosome.setGene(i, _firstParentChromosome.getGene(j));
                }
            }
        }
    }
}
